﻿using System;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace CalendarWindowsApp.Controls
{
    /// <summary>
    /// A panel that expands children containers to fill the parent continer horizontally or vertiacally.
    /// </summary>
    public class DynamicPanel : Panel
    {
        public static readonly DependencyProperty ProportionProperty =
             DependencyProperty.RegisterAttached("Proportion",
             typeof(double),
             typeof(DynamicPanel),
             new PropertyMetadata(1.0));

        public static double GetProportion(DependencyObject obj)
        {
            return (double)obj.GetValue(ProportionProperty);
        }

        public static void SetProportion(DependencyObject obj, double value)
        {
            obj.SetValue(ProportionProperty, value);
        }

        public Orientation Orientation
        {
            get
            {
                return (Orientation)GetValue(OrientationProperty);
            }
            set
            {
                SetValue(OrientationProperty, value);
            }
        }

        public static readonly DependencyProperty OrientationProperty =
            DependencyProperty.Register("Orientation",
            typeof(Orientation),
            typeof(DynamicPanel),
            new PropertyMetadata(Orientation.Horizontal));

        protected override Size MeasureOverride(Size availableSize)
        {
            if (this.Orientation == Orientation.Horizontal)
            {
                Size SizeForChildren = new Size(double.PositiveInfinity, availableSize.Height);
                double TotalWidth = 0;
                double MaxHeight = 0;
                foreach (UIElement Child in Children)
                {
                    Child.Measure(SizeForChildren);
                    TotalWidth += Child.DesiredSize.Width;
                    MaxHeight = Math.Max(MaxHeight, Child.DesiredSize.Height);
                }

                return new Size()
                {
                    Width = Math.Min(TotalWidth, availableSize.Width),
                    Height = double.IsInfinity(availableSize.Height) ? MaxHeight : availableSize.Height
                };
            }
            else
            {
                Size SizeForChildren = new Size(availableSize.Width, double.PositiveInfinity);
                double TotalHeight = 0;
                double MaxWidth = 0;
                foreach (UIElement Child in Children)
                {
                    Child.Measure(SizeForChildren);
                    TotalHeight += Child.DesiredSize.Height;
                    MaxWidth = Math.Max(MaxWidth, Child.DesiredSize.Width);
                }

                return new Size()
                {
                    Width = double.IsInfinity(availableSize.Width) ? MaxWidth : availableSize.Width,
                    Height = Math.Min(TotalHeight, availableSize.Height)
                };
            }
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            double totalProportion = 0;
            double fixedHeight = 0;
            double fixedWidth = 0;
            if (this.Orientation == Orientation.Horizontal)
            {
                foreach (UIElement child in Children)
                {
                    double ChildProportion = GetProportion(child);
                    if (ChildProportion == 0)
                    {
                        fixedWidth += child.DesiredSize.Width;
                    }
                    else
                    {
                        totalProportion += ChildProportion;
                    }
                }
                double VariableWidth = Math.Max(finalSize.Width - fixedWidth, 0);

                Rect rectChild = new Rect();
                foreach (UIElement Child in this.Children)
                {
                    double ChildProportion = GetProportion(Child);
                    if (ChildProportion == 0)
                    {
                        rectChild.Width = Child.DesiredSize.Width;
                    }
                    else
                    {
                        rectChild.Width = ChildProportion / totalProportion * VariableWidth;
                    }
                    rectChild.Y = 0;
                    rectChild.Height = finalSize.Height;
                    FrameworkElement ChildElement = Child as FrameworkElement;
                    if (ChildElement != null)
                    {
                        if (ChildElement.VerticalAlignment != VerticalAlignment.Stretch)
                        {
                            rectChild.Height = Child.DesiredSize.Height;
                        }
                        switch (ChildElement.VerticalAlignment)
                        {
                            case VerticalAlignment.Top:
                            case VerticalAlignment.Stretch:
                                rectChild.Y = 0;
                                break;

                            case VerticalAlignment.Bottom:
                                rectChild.Y = finalSize.Height - rectChild.Height;
                                break;

                            case VerticalAlignment.Center:
                                rectChild.Y = (finalSize.Height - rectChild.Height) / 2;
                                break;
                        }
                    }
                    Child.Arrange(rectChild);
                    rectChild.X += rectChild.Width;
                }
            }
            else
            {
                foreach (UIElement Child in Children)
                {
                    double ChildProportion = GetProportion(Child);
                    if (ChildProportion == 0)
                    {
                        fixedHeight += Child.DesiredSize.Height;
                    }
                    else
                    {
                        totalProportion += ChildProportion;
                    }
                }
                double VariableHeight = Math.Max(finalSize.Height - fixedHeight, 0);

                Rect rectChild = new Rect();
                foreach (UIElement Child in Children)
                {
                    double ChildProportion = GetProportion(Child);
                    if (ChildProportion == 0)
                    {
                        rectChild.Height = Child.DesiredSize.Height;
                    }
                    else
                    {
                        rectChild.Height = ChildProportion / totalProportion * VariableHeight;
                    }
                    rectChild.X = 0;
                    rectChild.Width = finalSize.Width;
                    FrameworkElement ChildElement = Child as FrameworkElement;
                    if (ChildElement != null)
                    {
                        if (ChildElement.HorizontalAlignment != HorizontalAlignment.Stretch)
                        {
                            rectChild.Width = Child.DesiredSize.Width;
                        }
                        switch (ChildElement.HorizontalAlignment)
                        {
                            case HorizontalAlignment.Left:
                            case HorizontalAlignment.Stretch:
                                rectChild.X = 0;
                                break;

                            case HorizontalAlignment.Right:
                                rectChild.X = finalSize.Width - rectChild.Width;
                                break;

                            case HorizontalAlignment.Center:
                                rectChild.X = (finalSize.Width - rectChild.Width) / 2;
                                break;
                        }
                    }
                    Child.Arrange(rectChild);
                    rectChild.Y += rectChild.Height;
                }
            }

            return finalSize;
        }
    }
}